/* eslint-disable no-unused-vars */
import express, { RequestHandler } from 'express'
import { parseToken } from '../utils/token'
import { Code, createResult } from '../db/common-model/result'
const result = createResult()
import User from '../db/user'
import { TokenType } from '../db/token'
import Admin from '../db/admin/index'

// 检查用户 token
const userTokenHandler: RequestHandler = req => new Promise(resolve => {
  const token = req.headers[global.Config.TOKEN_KEY] as string

  parseToken(token).then(tokenData => {
    const now = Date.now()
    const exp = tokenData.exp || 0
    if (tokenData.type !== TokenType.User) {
      resolve('token 类型不正确')
    }

    if (now < exp) {
      User.getUserByUsernameAndPassword({
        username: tokenData.username as string,
        password: tokenData.password as string,
      }).then(user => {
        // 是否存在该用户信息
        if (user) {
          req.query.user = user as any
          resolve(undefined)
        } else {
          resolve('登录信息不存在请重新登录')
        }
      })
    } else {
      resolve('登录信息已过期')
    }
  }).catch(resolve)
})

// 检查管理员 token
const adminTokenHandler: RequestHandler = req => new Promise(resolve => {
  const token = req.headers[global.Config.TOKEN_KEY] as string

  parseToken(token).then(tokenData => {
    const now = Date.now()
    const exp = tokenData.exp || 0
    if (tokenData.type !== TokenType.Admin) {
      resolve('token 类型不正确')
    }

    if (now < exp) {
      Admin.getAdminByUsernameAndPassword({
        username: tokenData.username as string,
        password: tokenData.password as string,
      }).then(admin => {
        // 是否存在该用户信息
        if (admin) {
          req.query.admin = admin as any
          resolve(undefined)
        } else {
          resolve('登录信息不存在请重新登录')
        }
      })
    } else {
      resolve('登录信息已过期')
    }
  }).catch(resolve)
})

enum CreateMethod {
  And = 'and',
  Or = 'or',
}

const createFilter = (method: CreateMethod, handles: RequestHandler[]): RequestHandler => {
  return async(req, res, next) => {
    // const cookie = req.cookies[global.Config.TOKEN_KEY]
    // const session = req.session[global.Config.SESSION_NAME]
    // const token = req.headers[global.Config.TOKEN_KEY] as string

    try {
      const resArray = await Promise.all(handles.map(item => item(req, res, next)))

      // 是否有返回错误
      const hasError = resArray.some(item => typeof item === 'string')
      // 是否全部返回错误
      const allError = resArray.every(item => typeof item === 'string')
      // 第一个错误，没有错误返回 undefined
      const errMsg = resArray.find(item => typeof item === 'string')

      if (
        (method === CreateMethod.And && hasError) ||
        (method === CreateMethod.Or && allError)
      ) {
        throw new Error((errMsg as any).toString())
      } else {
        next()
      }
    } catch (error) {
      result.code = Code.AuthError
      const err = error as Error
      result.msg = err.message || '还未登录或登录信息已过期'
      res.send(result)
      // 如果是普通错误不输出到日志
      err.name !== 'Error' && next(err)
    }
  }
}

const and = (...handles: RequestHandler[]) => {
  const filter = express.Router()
  filter.use(createFilter(CreateMethod.And, handles))
  return filter
}

const or = (...handles: RequestHandler[]) => {
  const filter = express.Router()
  filter.use(createFilter(CreateMethod.Or, handles))
  return filter
}

const use = (handle: RequestHandler) => and(handle)

export default {
  user: userTokenHandler,
  admin: adminTokenHandler,
  and,
  or,
  use,
}
